/**
 * Copyright 2019-2020 Huawei Technologies Co., Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "common/util/json_util.h"
#include <climits>
#include <fstream>
#include "common/fe_log.h"
#include "common/fe_utils.h"
#include "common/aicore_util_constants.h"
#include "common/fe_error_code.h"

namespace fe {
std::string RealPath(const std::string &path) {
  if (path.empty()) {
    FE_LOGI("path string is nullptr.");
    return "";
  }
  if (path.size() >= PATH_MAX) {
    FE_LOGI("file path %s is too long! ", path.c_str());
    return "";
  }

  // PATH_MAX is the system marco，indicate the maximum length for file path
  // pclint check，one param in stack can not exceed 1K bytes
  char resoved_path[PATH_MAX] = {0x00};

  std::string res = "";

  // path not exists or not allowed to read，return nullptr
  // path exists and readable, return the resoved path
  if (nullptr != realpath(path.c_str(), resoved_path)) {
    res = resoved_path;
  } else {
    FE_LOGI("path %s is not exist.", path.c_str());
  }
  return res;
}

Status ReadJsonFile(const std::string &file, nlohmann::json &json_obj) {
  std::string real_path = RealPath(file);
  if (real_path.empty()) {
    FE_LOGW("file path '%s' not valid", file.c_str());

    std::map<std::string, std::string> error_key_map;
    error_key_map[EM_ERROR_MSG] = "The file does not exist.";
    error_key_map[EM_FILE] = file;
    LogErrorMessage(EM_OPEN_FILE_FAILED, error_key_map);
    return FAILED;
  }
  std::ifstream ifs(real_path);
  try {
    if (!ifs.is_open()) {
      FE_LOGW("Open %s failed, file is already open", file.c_str());

      std::map<std::string, std::string> error_key_map;
      error_key_map[EM_ERROR_MSG] = "The file is already open.";
      error_key_map[EM_FILE] = file;
      LogErrorMessage(EM_OPEN_FILE_FAILED, error_key_map);
      return FAILED;
    }
    ifs >> json_obj;
    ifs.close();
  } catch (const std::exception &e) {
    FE_LOGW("Fail to convert file[%s] to Json. Error message is %s.", real_path.c_str(), e.what());
    ifs.close();

    std::map<std::string, std::string> error_key_map;
    error_key_map[EM_ERROR_MSG] = e.what();
    error_key_map[EM_FILE] = file;
    LogErrorMessage(EM_READ_FILE_FAILED, error_key_map);
    return ILLEGAL_JSON;
  }

  return SUCCESS;
}

std::string GetJsonType(const nlohmann::json &json_object) {
  std::string json_type;

  switch (json_object.type()) {
    case nlohmann::json::value_t::null:
      json_type = "null";
      break;
    case nlohmann::json::value_t::object:
      json_type = "object";
      break;
    case nlohmann::json::value_t::array:
      json_type = "array";
      break;
    case nlohmann::json::value_t::string:
      json_type = "string";
      break;
    case nlohmann::json::value_t::boolean:
      json_type = "boolean";
      break;
    case nlohmann::json::value_t::number_integer:
      json_type = "number_integer";
      break;
    case nlohmann::json::value_t::number_unsigned:
      json_type = "number_unsigned";
      break;
    case nlohmann::json::value_t::number_float:
      json_type = "number_float";
      break;
    case nlohmann::json::value_t::discarded:
      json_type = "discarded";
      break;
  }

  return json_type;
}
}  // namespace fe